home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 352_01 / strpprep.cpp < prev    next >
C/C++ Source or Header  |  1991-04-28  |  4KB  |  138 lines

  1. // STRPPREP.CPP  contains String::replace()
  2. //
  3. //    routine to replace all occurences of char *original with char *replace.
  4. //    lengths of two strings do not have to be equal.
  5. //    detection of char *ori obeys String::caseSens
  6. //
  7. //  METHOD: This is a table driven routine.
  8. //            The table is a list of all positions in *this where ori occurs.
  9. //            The table is allocated dynamically, 
  10. //                large enough to hold the maximum number of occurences = this->n
  11. //            The table is filled in by repeated calls to String::findstr()
  12. //                which looks for successive occurences of ori.
  13. //            Computing size following replacements
  14. //            A new string is allocated
  15. //            The first bytes of *this are moved in up to the first occurence.
  16. //            LOOP for each occurence:
  17. //                move in the replacement string.
  18. //                move in bytes from the *this string after current occurence
  19. //                                                    and before next occurence.
  20. //            swap strings. free workareas.        
  21. //    D Blum 8/90
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include "wtwg.h"
  25. #include "dblib.h"
  26.  
  27. static char NULLstring =0;
  28.  
  29. String& String::replace (char *ori, char *rep)
  30.     {
  31.     int sn = n;
  32.     char *ss = s;
  33.     if ( ori == NULL ) ori = &NULLstring;
  34.     int lo = strlen (ori);
  35.     if ( rep==NULL ) rep = &NULLstring;
  36.     int lr = strlen (rep);
  37.     int lresult;                // number of bytes in result string.
  38.     int k=0;                    // count occurences of ori in *this.
  39.     char *stmp;                    // the new string to build up
  40.     char *stmp_p, *ss_p;        // position ptr in string stmp and ss;
  41.     int this_pos,  next_pos, interval;                    
  42.     
  43.     // make sure that original string and *this string are not NULL
  44.     //        (see end of routine)
  45.     //
  46.     if ( lo == 0 || sn == 0 ) return *this;
  47.  
  48.  
  49.     // position array - one int for each occurence of ori in *this.
  50.     //         maximum possible number of occurences is #bytes in *this.
  51.     int *pos;
  52.     pos = (int*) wmalloc ( sizeof(int)*sn, "String::replace" );
  53.     // fill in array with all occurences.
  54.     this_pos =-1;
  55.     do     {
  56.         // NOTE somewhat complicated indexing
  57.         //        guarantees stepping past last occurence detected.
  58.         //         this_pos starts at -1 so that this_pos+1 starts at 0.
  59.         //
  60.         interval = findstr(ss+this_pos+1, sn-this_pos-1, ori);
  61.  
  62.         if ( interval >= 0 )
  63.             {
  64.             this_pos += 1+interval;        // compensate for the +1 in findstr()
  65.             pos[k++] = this_pos;
  66.             }
  67.         else    break;
  68.         }
  69.     while ( k< sn );
  70.     
  71.     if ( k== 0 ) return *this;        // none found.
  72.         
  73.     //  allocate a new string large enough to hold result of replacements.
  74.     //    
  75.     lresult = sn + k*(lr-lo);                    // old len + #bytes change.
  76.     stmp = (char*)wmalloc ( lresult+1, "String::replace" );
  77.  
  78.     // copy all of *this that precedes first occurrence of *ori.
  79.     //    NOTE use next_pos here
  80.     //        so that loop that follows can move next_pos into this_pos
  81.     next_pos = pos[0];
  82.     if ( next_pos > 0 )
  83.         {
  84.         memcpy ( stmp, ss, next_pos );    
  85.         }
  86.     stmp_p = stmp + next_pos;        // move ptrs in result string 
  87.     ss_p   = ss   + next_pos;        // and source string by amount just moved.
  88.     int i=0;
  89.     do     {
  90.         this_pos = next_pos;
  91.         
  92.         // move in rep string, incr two ptrs at different rates.
  93.         memcpy ( stmp_p, rep, lr );
  94.         ss_p += lo;            // source ptr moves by size of original (bypassed) 
  95.         stmp_p += lr;        // result ptr moves by size of replacement.
  96.         
  97.         ++i;
  98.             
  99.         if ( i<k )        // there's another occurence coming up 
  100.             {
  101.             next_pos = pos[i];
  102.             
  103.             // test for intervening bytes in source between the two occurences 
  104.             interval = next_pos - this_pos - lo;
  105.             if ( interval > 0 )
  106.                 {
  107.                 memcpy ( stmp_p, ss_p,  interval);
  108.                 ss_p += interval;     
  109.                 stmp_p += interval;
  110.                 }
  111.             }
  112.         else
  113.             // all occurences have been moved.
  114.             {
  115.             // move any possible remainder of the source string
  116.             //        that follows the last occurence.
  117.             interval = sn -this_pos -lo;
  118.             if  ( interval > 0 )
  119.                 {
  120.                 memcpy ( stmp_p, ss_p, interval );
  121.                 // dont need to move ptrs - at end of loop
  122.                 }
  123.             break;
  124.             }
  125.         }
  126.     while ( 1 );        // NOTE break statement above.
  127.     
  128.     stmp [ lresult ] = 0;        
  129.     
  130.     free (s);            // NOTE we already know s is not NULL.
  131.     free ( pos );
  132.     
  133.     s = stmp;            // setup 'this' to point to result.
  134.     n = lresult;
  135.     
  136.     return *this;        
  137.     }        // end of String::replace() 
  138.